#include "../sylar/sylar.h"

sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("fiber_test");

// 测试纤维状态转换
void test_fiber_state() {
    SYLAR_LOG_INFO(g_logger) << "开始测试纤维状态转换";

    // 测试主纤维初始化
    sylar::Fiber::ptr main_fiber = sylar::Fiber::GetThis();
    SYLAR_ASSERT(main_fiber->getState() == sylar::Fiber::EXEC);
    SYLAR_LOG_INFO(g_logger) << "主纤维初始化状态正确: EXEC";

    // 测试新建纤维初始状态
    sylar::Fiber::ptr fiber(new sylar::Fiber([](){}));
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::INIT);
    SYLAR_LOG_INFO(g_logger) << "新建纤维初始状态正确: INIT";

    // 测试纤维执行后状态
    bool executed = false;
    fiber.reset(new sylar::Fiber([&executed](){
        executed = true;
        SYLAR_LOG_INFO(g_logger) << "子纤维执行完毕";
    }));
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::INIT);
    
    // 保存主纤维上下文，避免直接切换导致的上下文丢失
    auto main_ctx = sylar::Scheduler::GetMainFiber();
    fiber->swapIn();  // 切换到子纤维执行
    SYLAR_ASSERT(executed);
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::TERM);
    SYLAR_LOG_INFO(g_logger) << "纤维执行后状态正确: TERM";

    // 显式切换回主纤维上下文
    main_ctx->swapIn();
    SYLAR_LOG_INFO(g_logger) << "纤维状态转换测试完成";
}

// 测试纤维yield功能
void test_fiber_yield() {
    SYLAR_LOG_INFO(g_logger) << "开始测试纤维yield功能";

    int step = 0;
    sylar::Fiber::ptr fiber(new sylar::Fiber([&step](){
        SYLAR_LOG_INFO(g_logger) << "子纤维开始执行";
        step = 1;
        sylar::Fiber::YieldToHold();  // 暂停纤维，状态变为HOLD
        
        step = 2;
        SYLAR_LOG_INFO(g_logger) << "子纤维恢复执行";
        sylar::Fiber::YieldToHold();  // 再次暂停
        
        step = 3;
        SYLAR_LOG_INFO(g_logger) << "子纤维执行完成";
    }));

    // 第一次切换进入
    fiber->swapIn();
    SYLAR_ASSERT(step == 1);
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::HOLD);
    SYLAR_LOG_INFO(g_logger) << "第一次yield后状态正确: HOLD";

    // 第二次切换进入
    fiber->swapIn();
    SYLAR_ASSERT(step == 2);
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::HOLD);
    SYLAR_LOG_INFO(g_logger) << "第二次yield后状态正确: HOLD";

    // 第三次切换进入(完成执行)
    fiber->swapIn();
    SYLAR_ASSERT(step == 3);
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::TERM);
    SYLAR_LOG_INFO(g_logger) << "执行完成后状态正确: TERM";

    SYLAR_LOG_INFO(g_logger) << "纤维yield功能测试完成";
}

// 测试纤维异常处理
void test_fiber_exception() {
    SYLAR_LOG_INFO(g_logger) << "开始测试纤维异常处理";

    sylar::Fiber::ptr fiber(new sylar::Fiber([](){
        SYLAR_LOG_INFO(g_logger) << "子纤维开始执行，准备抛出异常";
        throw std::runtime_error("测试纤维异常");
    }));

    fiber->swapIn();
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::EXCEPT);
    SYLAR_LOG_INFO(g_logger) << "异常后状态正确: EXCEPT";

    SYLAR_LOG_INFO(g_logger) << "纤维异常处理测试完成";
}

// 测试纤维重置功能
void test_fiber_reset() {
    SYLAR_LOG_INFO(g_logger) << "开始测试纤维重置功能";

    int count = 0;
    sylar::Fiber::ptr fiber(new sylar::Fiber([&count](){
        count++;
    }));

    fiber->swapIn();
    SYLAR_ASSERT(count == 1);
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::TERM);

    // 重置纤维
    fiber->reset([&count](){
        count++;
    });
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::INIT);

    fiber->swapIn();
    SYLAR_ASSERT(count == 2);
    SYLAR_ASSERT(fiber->getState() == sylar::Fiber::TERM);

    SYLAR_LOG_INFO(g_logger) << "纤维重置功能测试完成";
}

// 测试多纤维切换
void test_multi_fiber() {
    SYLAR_LOG_INFO(g_logger) << "开始测试多纤维切换";

    int val1 = 0, val2 = 0;
    sylar::Fiber::ptr fiber1(new sylar::Fiber([&val1](){
        for(int i = 0; i < 3; ++i) {
            val1++;
            SYLAR_LOG_INFO(g_logger) << "纤维1执行，val1=" << val1;
            sylar::Fiber::YieldToHold();
        }
    }));

    sylar::Fiber::ptr fiber2(new sylar::Fiber([&val2](){
        for(int i = 0; i < 3; ++i) {
            val2++;
            SYLAR_LOG_INFO(g_logger) << "纤维2执行，val2=" << val2;
            sylar::Fiber::YieldToHold();
        }
    }));

    // 交替执行两个纤维
    for(int i = 0; i < 3; ++i) {
        fiber1->swapIn();
        fiber2->swapIn();
    }

    SYLAR_ASSERT(val1 == 3);
    SYLAR_ASSERT(val2 == 3);
    SYLAR_LOG_INFO(g_logger) << "多纤维交替执行完成";

    SYLAR_LOG_INFO(g_logger) << "多纤维切换测试完成";
}

int main() {
    sylar::InitUtil();
    SYLAR_LOG_INIT();

    SYLAR_LOG_INFO(g_logger) << "======= 纤维测试开始 =======";
    
    // 记录初始纤维数量（主纤维会在GetThis()时创建）
    sylar::Fiber::ptr main_fiber = sylar::Fiber::GetThis();
    uint64_t initial_count = sylar::Fiber::TotalFibers();
    SYLAR_LOG_INFO(g_logger) << "初始纤维数量: " << initial_count;

    test_fiber_state();
    test_fiber_yield();
    test_fiber_exception();
    test_fiber_reset();
    test_multi_fiber();

    // 验证纤维总数
    SYLAR_LOG_INFO(g_logger) << "最终纤维数量: " << sylar::Fiber::TotalFibers();
    
    SYLAR_LOG_INFO(g_logger) << "======= 纤维测试结束 =======";
    return 0;
}